/***************************************************************************
 * Copyright (C) 2012
 * by Dj_Skual
 *
 * Original ListBrowser by Tantric (C) 2009
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you
 * must not claim that you wrote the original software. If you use
 * this software in a product, an acknowledgment in the product
 * documentation would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and
 * must not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 * distribution.
 *
 * for SaveGame Manager GX 2012
 ***************************************************************************/
#include "ListGCBrowser.hpp"
#include "../../Themes/CTheme.h"
#include "../../Controls/Application.h"

/**
 * Constructor for the ListGCBrowser class.
 */
ListGCBrowser::ListGCBrowser(Browser * gcbrowser, int w, int h)
	: GuiFileBrowser(gcbrowser, w, h)
{
	selectedItem = 0;
	pageIndex = 0;
	forceReload = true;
	numEntries = browser->GetEntrieCount();
	
	browser->ListChanged.connect(this, &ListGCBrowser::OnBrowserListChange);

	trigA = new GuiTrigger;
	trigA->SetSimpleTrigger(-1, WiiControls.ClickButton | ClassicControls.ClickButton << 16, GCControls.ClickButton);

	btnSoundClick = Resources::GetSound("button_click.wav");

	bgFileSelection = Resources::GetImageData("browser_bg_selection.png");
	fileGC = Resources::GetImageData("icon_brows_gc.png");
	
	separator = Resources::GetImageData("browser_separator.png");
	separatorImg = new GuiImage(separator);
	separatorImg->SetAlignment(ALIGN_LEFT | ALIGN_TOP);
	separatorImg->SetPosition(thInt("384 - mainbrowser list separator pos x"), 0);
	Append(separatorImg);
	
	scrollbar = new Scrollbar(height + 20, Scrollbar::LISTMODE);
	scrollbar->SetAlignment(ALIGN_RIGHT | ALIGN_TOP);
	scrollbar->SetPosition(4, -10);
	scrollbar->SetScrollSpeed(Settings.ScrollSpeed);
	scrollbar->SetDPadControl(false);
	scrollbar->listChanged.connect(this, &ListGCBrowser::OnListChange);
	
	infosWindow = new GCInfosWindow(browser, width-thInt("384 - mainbrowser list separator pos x")-separator->GetWidth()-scrollbar->GetWidth()-16, height-40);
	infosWindow->SetPosition(thInt("384 - mainbrowser list separator pos x")+separator->GetWidth()+10, 20);
	Append(infosWindow);
	
	PageSize = height/30;
	
	for(int i = 0; i < PageSize; ++i)
		AddButton();
	
	scrollbar->SetEntrieCount(numEntries);
	scrollbar->SetPageSize(PageSize);
	scrollbar->SetSelected(0, 0);
	Append(scrollbar);
	
	SetVisible(false);
	VisibleChanged.connect(this, &ListGCBrowser::OnVisibleChange);
}

/**
 * Destructor for the ListGCBrowser class.
 */
ListGCBrowser::~ListGCBrowser()
{
	RemoveAll();
	
	Resources::Remove(btnSoundClick);
	
	delete separatorImg;
	
	Resources::Remove(separator);
	Resources::Remove(bgFileSelection);
	Resources::Remove(fileGC);
	
	delete trigA;

	delete scrollbar;
	delete infosWindow;
	
	while(!fileBtn.empty())
		RemoveButton(0);
}

void ListGCBrowser::AddButton()
{
	int size = fileBtn.size();

	fileSelectionImg.resize(size+1);
	fileSelectionImg[size] = new GuiImage(bgFileSelection);
	
	fileBtnText.resize(size+1);
	fileBtnText[size] = new GuiText((char*) NULL, 20, thColor("r=0 g=0 b=0 a=255 - mainbrowser entry text color"));
	fileBtnText[size]->SetAlignment(ALIGN_LEFT | ALIGN_MIDDLE);
	fileBtnText[size]->SetPosition(38,0);
	fileBtnText[size]->SetMaxWidth(thInt("384 - mainbrowser list separator pos x") - 38, DOTTED);

	fileBtnTextOver.resize(size+1);
	fileBtnTextOver[size] = new GuiText((char*) NULL, 20, thColor("r=0 g=0 b=0 a=255 - mainbrowser entry text color"));
	fileBtnTextOver[size]->SetAlignment(ALIGN_LEFT | ALIGN_MIDDLE);
	fileBtnTextOver[size]->SetPosition(38,0);
	fileBtnTextOver[size]->SetMaxWidth(thInt("384 - mainbrowser list separator pos x") - 52, SCROLL_HORIZONTAL);

	fileBtnIcon.resize(size+1);
	fileBtnIcon[size] = new GuiImage(fileGC);
	fileBtnIcon[size]->SetScale(0.667);
	fileBtnIcon[size]->SetPosition(0,-7);
	
	fileBtn.resize(size+1);
	fileBtn[size] = new GuiButton(thInt("384 - mainbrowser list separator pos x")-2,30);
	fileBtn[size]->SetPosition(2,30*size+3);
	fileBtn[size]->SetLabel(fileBtnText[size]);
	fileBtn[size]->SetLabelOver(fileBtnTextOver[size]);
	fileBtn[size]->SetImageOver(fileSelectionImg[size]);
	fileBtn[size]->SetIcon(fileBtnIcon[size]);
	fileBtn[size]->SetTrigger(trigA);
	fileBtn[size]->SetSoundClick(btnSoundClick);
	fileBtn[size]->SetRumble(Settings.BrowserRumble);
	fileBtn[size]->Clicked.connect(this, &ListGCBrowser::OnClicked);
	fileBtn[size]->StateChanged.connect(this, &ListGCBrowser::OnButtonStateChange);
	fileBtn[size]->SetState(STATE_DISABLED);
	
	Append(fileBtn[size]);
}

void ListGCBrowser::RemoveButton(int i)
{
	if(i < 0 || i >= (int) fileBtn.size())
		return;

	if(fileBtnTextOver[i])
		delete fileBtnTextOver[i];
	if(fileBtnText[i])
		delete fileBtnText[i];
	if(fileSelectionImg[i])
		delete fileSelectionImg[i];
	if(fileBtnIcon[i])
		delete fileBtnIcon[i];
	if(fileBtn[i])
		delete fileBtn[i];

	fileBtnTextOver.erase(fileBtnTextOver.begin()+i);
	fileBtnText.erase(fileBtnText.begin()+i);
	fileSelectionImg.erase(fileSelectionImg.begin()+i);
	fileBtnIcon.erase(fileBtnIcon.begin()+i);
	fileBtn.erase(fileBtn.begin()+i);
}

void ListGCBrowser::SetListRumble()
{
	for(int i = 0; i < (int)fileBtn.size(); i++)
		fileBtn[i]->SetRumble(Settings.BrowserRumble);
}

void ListGCBrowser::OnVisibleChange(GuiElement *sender UNUSED, bool Visible)
{
	if(Visible)
	{
		forceReload = true;
		OnListChange(selectedItem, pageIndex);
	}
}

void ListGCBrowser::OnClicked(GuiButton *sender, int pointer UNUSED, const POINT &p UNUSED)
{
	Application::Instance()->ResetPads();
	
	for(u32 i = 0; i < fileBtn.size(); i++)
	{
		if(fileBtn[i] == sender)
		{
			Clicked(i);
			break;
		}
	}
}

void ListGCBrowser::OnButtonStateChange(GuiElement *sender, int state, int stateChan UNUSED)
{
	if(scrollbar->BoxIsHolded())
		goto jump;
	
	for(int i = 0; i < PageSize && i < numEntries; i++)
	{
		if(sender == fileBtn[i])
		{
			if(state == STATE_SELECTED)
			{
				selectedItem = i;
				browser->SetSelectedIndex(pageIndex+i);
				break;
			}
		}
	}
	
  jump:
	
	if(fileBtn[selectedItem]->GetState() == STATE_DEFAULT)
		fileBtn[selectedItem]->_SetState(STATE_SELECTED);
	
	scrollbar->SetSelectedItem(selectedItem);
}

void ListGCBrowser::OnListChange(int selItem, int selIndex)
{
	static bool changing = false;
	if(changing)
		return;
	changing = true;
	
	bool reloadNeeded = false;
	if((pageIndex != selIndex) || forceReload)
		reloadNeeded = true;
	forceReload = false;
	
	pageIndex = selIndex;
	selectedItem = selItem;
	browser->SetSelectedIndex(selIndex+selItem);
	
	for(int i = 0; i < PageSize && reloadNeeded; i++)
	{
		if(selIndex+i < numEntries)
		{
			if(fileBtn[i]->GetState() == STATE_DISABLED)
			{
				fileBtn[i]->SetVisible(true);
				fileBtn[i]->SetState(STATE_DEFAULT);
			}
			
			std::wstring name = browser->GetGCName(selIndex+i);
			fileBtnText[i]->SetText(name);
			fileBtnTextOver[i]->SetText(name);
		}
		else
		{
			fileBtn[i]->SetVisible(false);
			fileBtn[i]->SetState(STATE_DISABLED);
		}
	}
	
	for(int i = 0; i < PageSize; i++)
	{
		if(fileBtn[i]->GetState() == STATE_SELECTED && i != selItem)
			fileBtn[i]->SetState(STATE_DEFAULT);
	}
	
	reloadNeeded = false;
	changing = false;
}

void ListGCBrowser::OnBrowserListChange()
{
	if(numEntries != browser->GetEntrieCount())
	{
		numEntries = browser->GetEntrieCount();
		scrollbar->SetEntrieCount(numEntries);
	}

	forceReload = true;
	OnListChange(0, 0);
	
	scrollbar->SetSelectedItem(0);
	scrollbar->SetSelectedIndex(0);
}

void ListGCBrowser::Update(GuiTrigger * t)
{
	bool ListChanged = false;
	
	if(t->Up())
	{
		if(selectedItem == 0 && pageIndex > 0)
		{
			--pageIndex;
			ListChanged = true;
		}
		else if(pageIndex+selectedItem > 0)
		{
			--selectedItem;
			ListChanged = true;
		}
	}
	else if(t->Down())
	{
		if(pageIndex+selectedItem + 1 < numEntries)
		{
			if(selectedItem == PageSize-1)
			{
				//! move list down by 1
				pageIndex++;
			}
			else
			{
				selectedItem++;
			}
			ListChanged = true;
		}
	}
	else if(t->Left())
	{
		if(pageIndex > 0)
		{
			pageIndex -= PageSize;
			if(pageIndex < 0)
			{
				pageIndex = 0;
				selectedItem = 0;
			}
			ListChanged = true;
		}
	}
	else if(t->Right())
	{
		if(pageIndex < MAX(0, (numEntries-PageSize)))
		{
			pageIndex += PageSize;
			if(pageIndex > numEntries-PageSize)
			{
				pageIndex = MAX(numEntries-PageSize, 0);
				selectedItem = LIMIT(PageSize-1, 0, numEntries-1);
			}
			ListChanged = true;
		}
	}
	
	if(ListChanged)
	{
		forceReload = true;
		OnListChange(selectedItem, pageIndex);
		
		scrollbar->SetSelectedItem(selectedItem);
		scrollbar->SetSelectedIndex(pageIndex);
	}
	
	GuiFileBrowser::Update(t);
}
